/***************************************************************************
 *   Copyright (C) 2006 by Harish Kukreja                                  *
 *   harish.kukreja@gmail.com                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//
// C++ Interface: objects
//
// Description: Headers for various physical Objects that are found in the Physiks interaction
//              environment.
//
// Author: Harish Kukreja <harish.kukreja@gmail.com>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//

#ifndef _OBJECTS_H_
#define _OBJECTS_H_

#include <physiksbase/fields.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_blas.h>

namespace PhysiksBase {

using namespace PhysiksBase;



/** \class PhysicalObject 
 * \brief The fundamental dynamic element of a simulation. */
class PhysicalObject {
    public:
        double mass;
        double charge;
        Vector position;
        Vector velocity;
        Vector net_force;
        
        /** Flag specifying whether or not this object should be fixed at a point in Rn */
        bool immovable;
        
        /** Gravitational field created by this object  */
        NewtonianGravitationalField gravitational_field;
        
        /** Coulomb (electric) acceleration field created by this object   */
        CoulombAccelerationField coulomb_acceleration_field;

        /** \brief  Default parameterless constructor. Mass and charge are initialised to 0, and
         * all vectors are initialised to the zero vector. */
        PhysicalObject();
        
        /** \brief  Explicit constructor.
         * \param   mass    the object's mass.
         * \param   charge  the object's charge.
         * \param   position    the object's initial position in n-space.
         * \param   velocity    the object's initial velocity in n-space. */
        PhysicalObject(double mass, double charge, const Vector &position,
                       const Vector &velocity);
        
        /** \brief Draws the OpenGL representation of this type of PhysicalObject. */
        virtual void draw() const;
        
        virtual ~PhysicalObject();
};

//=============================================================================

class ExtendedObject : public PhysicalObject {
    public:
        Vector angular_velocity;
        
        /** \brief  Default parameterless constructor. In addition to the initialisations of 
         * PhysicalObject's parameterless constructor, angular_velocity is initialised to the zero.
         * vector. */
        ExtendedObject();
        
        /** \brief  Explicit constructor.
         * \param   angular_velocity    the extended object's angular velocity. */
        ExtendedObject(double mass, double charge, const Vector &position, const Vector &velocity);
        
        virtual ~ExtendedObject();
};

//=============================================================================

class Sphere : public ExtendedObject {
    protected:
        double radius;
        
        /** This sphere's constant surface elasticity. Used primarily for collision reaction */
        double elasticity;
        
    public:
        /** \brief  Default parameterless constructor. In addition to the initialisations of
         * ExtendedObject's parameterless constructor, radius is initialised to 1. */
        Sphere();
        
        /** \brief  Explicit constructor.
         * \param   radius  the spherical object's radius. */
        Sphere(double mass, double charge, const Vector &position, const Vector &velocity, 
               double radius);
        
        virtual ~Sphere();
        
        /** \brief Draws a sphere at the appropriate location in GL-space, representing this
         *         instance. */
        void draw() const;
        
        double get_radius() const;
        void set_radius(double radius);
        double get_elasticity() const;
        void set_elasticity(double val);
};

//=============================================================================

class Plane : public ExtendedObject {
    protected:
        /** \brief  Flag controlling the nature of the plane's interactions with other objects.
         * 
         * If true, the plane is taken to be infinite (i.e. the set of ALL linear combinations of
         * the two basis vectors. Otherwise, it is restricted to the set of all linear combinations
         * of the two basis vectors with coefficients <= 1. In this way, the length and breadth of
         * the bounded plane are specified by the magnitudes of basis_vec1 and basis_vec2. */
        bool unbounded;

    public:
        /** The plane's unit normal vector. */
        Vector *normal_vec;

        /** One of the plane's two basis vectors. */
        Vector *basis_vec1;
        
        /** The second of the plane's two basis vectors. */
        Vector *basis_vec2;
        

        Plane(const Vector &normal, const Vector &origin);

        /** \brief  Explicit constructor.
         * \param   vec1    Basis vector 1 for the plane.
         * \param   vec2    Basis vector 2 for the plane.
         * \param   origin  the common base of vec1 and vec2.   */
        Plane(const Vector &vec1, const Vector &vec2, const Vector &origin);
        
        virtual ~Plane();
        
        void draw() const;
        
        /** \brief  Set the plane's unbounded flag.
         * \param   flag    true if the plane must be bounded, false otherwise. */
        void bounded(bool flag);
        
        /** \brief  Returns the value of the plane's ``bounded'' flag
         * \return  True if the plane is bounded, false otherwise. */
        bool bounded() const;
        
        bool contains(const Vector &vec) const;
        
        
        /** Returns a unit vector normal to this plane  */
        Vector normal() const;
        
        /** Sets this plane's normal vector */
        void set_normal(const Vector &norm);
};



}   // End of namespace PhysiksBase

#endif
